package com.woniuxy.moneyapp.app.controller;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.commons.exception.MyException;
import com.woniuxy.commons.util.*;
import com.woniuxy.moneyapp.app.controller.form.RechargeStateInfo;
import com.woniuxy.moneyapp.app.createJob.XxlJobCreateParam;
import com.woniuxy.moneyapp.app.createJob.XxlJobManager;
import com.woniuxy.moneyapp.client.ReturnCashClient;
import com.woniuxy.moneyapp.client.param.BalanceRefundForm;
import com.woniuxy.moneyapp.client.param.SendRefundRequest;
import com.woniuxy.moneyapp.common.enums.PaymentRelated;
import com.woniuxy.moneyapp.common.enums.SchemaCode;
import com.woniuxy.moneyapp.common.exception.code.FundExceptionCode;
import com.woniuxy.moneyapp.common.utils.CommonUtil;
import com.woniuxy.moneyapp.infra.dto.BalancePayDto;
import com.woniuxy.moneyapp.infra.dto.RefundInfo;
import com.woniuxy.moneyapp.infra.model.PayRecord;
import com.woniuxy.moneyapp.service.PayRecordService;
import com.woniuxy.ptapp.client.ClassesOrderClient;
import com.woniuxy.ptapp.client.param.ClassesOrderDto;
import com.woniuxy.userapp.client.FrontAccountClient;
import com.woniuxy.userapp.client.StudentClient;
import com.woniuxy.userapp.client.VenueClient;
import com.woniuxy.userapp.client.param.AutoDeductMoneyInfo;
import com.woniuxy.userapp.client.param.StudentInfo;
import com.woniuxy.userapp.client.param.VenueInfo;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author seven
 * @since 2022-08-01
 */
@RestController
public class ReturnCashController implements ReturnCashClient {

    @Resource
    private PayRecordService payRecordService;

    @Resource
    private ClassesOrderClient coc;

    @Resource
    private FrontAccountClient userClient;

    @Resource
    private RocketMQTemplate rt;

    @Resource
    private XxlJobManager xxl;

    @Resource
    private StringRedisTemplate srt;

    @Resource
    private StudentClient sc;

    @Resource
    private VenueClient vc;



    @Override
    public Result regularRefund(BalanceRefundForm bp) throws JsonProcessingException, UnsupportedEncodingException {
        //场景识别 支付宝退款失败 余额退款失败
        Integer a = null;

        //获取账户信息
        //根据token 查用户id 用户名
        LoginUserDto userDto = GetTokenUserLogin.getTokenUserLogin();
        //前台帐户id
        Integer uid = userDto.getLoginId();
        //前台帐户用户名
        String userName = userDto.getLoginName();


        //订单前置判断
        if (bp.getOrderId() == null)
            throw new MyException(FundExceptionCode.PARAM_NULL.getCode(), FundExceptionCode.PARAM_NULL.getMsg());
        //根据订单id 查到订单对象 里面有交易订单号
        //返回null 提示订单不存在
        Result<ClassesOrderDto> corder = coc.getClassesOrderById(bp.getOrderId());
        ClassesOrderDto co = corder.getData();
        if (corder.getData() == null)
            throw new MyException(FundExceptionCode.ORDER_NULL.getCode(), FundExceptionCode.ORDER_NULL.getMsg());
        Result<VenueInfo> venueByAccountId = vc.findVenueByAccountId(uid);
        VenueInfo venueInfo = venueByAccountId.getData();
        if(venueInfo==null)
            throw new MyException(FundExceptionCode.NOT_VENUE_ACC.getCode(), FundExceptionCode.NOT_VENUE_ACC.getMsg());
        if(co.getVenueId().intValue()!=venueInfo.getId().intValue())
            throw new MyException(FundExceptionCode.NOT_THIS_ACC.getCode(), FundExceptionCode.NOT_THIS_ACC.getMsg());
        if(co.getState()!=14)
            throw new MyException(FundExceptionCode.REFUND_NOT_COMMIT.getCode(), FundExceptionCode.REFUND_NOT_COMMIT.getMsg());
        //金额前置判断
        if(bp.getCashAmount()==null) bp.setCashAmount(co.getPrice().toString());
        if(co.getPrice().compareTo(new BigDecimal(bp.getCashAmount())) < 0)
            throw new MyException(FundExceptionCode.CANNOT_BIGGER.getCode(), FundExceptionCode.CANNOT_BIGGER.getMsg());
        //判断该订单是否在退款
        if(srt.opsForValue().get("return_cash:save:info:" + co.getOrderNum())!=null)
            throw new MyException(FundExceptionCode.REFUND_ON_WORKING.getCode(), FundExceptionCode.REFUND_ON_WORKING.getMsg());
        //避免过重复退款
        String s = srt.opsForValue().get("return_cash:save:info:done" +co.getOrderNum());
        if(s!=null)
            throw new MyException(FundExceptionCode.REFUND_HAS_DONE.getCode(), FundExceptionCode.REFUND_HAS_DONE.getMsg());
        Result<Integer> stuInfo = sc.findAccountIdByStudentId(co.getStudentId());
        Integer data = stuInfo.getData();
        if(data==null)
            throw new MyException(FundExceptionCode.STUDENT_NOT_EXISTS.getCode(), FundExceptionCode.STUDENT_NOT_EXISTS.getMsg());



        srt.opsForValue().set("return_cash:save:info:" + co.getOrderNum(),"on_working",10, TimeUnit.SECONDS);

        //记录
        PayRecord payRecord = new PayRecord();
        payRecord.setScence(SchemaCode.REFUND_CODE.getNum());
        payRecord.setPaymentWay(PaymentRelated.ALIPAY_NAME.getDesc());
        payRecord.setCashAmount(new BigDecimal(bp.getCashAmount()));
        payRecord.setState(0);
        String serialNum = CommonUtil.getRechargeCode(SchemaCode.SERIAL_CODE.getNum());
        payRecord.setPayNum(serialNum);
        payRecord.setOrderNum(co.getOrderNum());
        payRecordService.save(payRecord);


        if(co.getPayment()==null)
            throw new MyException(FundExceptionCode.PARAM_NULL.getCode(),FundExceptionCode.PARAM_NULL.getMsg());
        //判断支付方式
        if (co.getPayment() == 0) {
            // 支付宝
            //是trade no 不是订单号 没有测试
            if (!CommonUtil.refund(co.getOrderNum(), co.getPrice())){
                //支付宝退款失败
                a = 1;
            }
        }
        if (co.getPayment() == 1) {
            //余额支付 走自定义
            //根据学员id 教练id 课程金额 更改用户余额
            //注意判断场馆余额！如果余额不足 返回错误编号6006 场馆余额不足
            //if(code==6006) 返回result 提示余额不足 定时任务（xxljob）
            //传订单id和场馆id进参数 查看订单状态 不是已退款状态 封店（更改场馆状态）
            System.out.println(co.getStudentId());
            Result<Integer> accountIdByStudentId = sc.findAccountIdByStudentId(co.getStudentId());
            if(accountIdByStudentId.getData()==null)
                throw new MyException(FundExceptionCode.RETURN_DATA_NULL.getCode(),FundExceptionCode.RETURN_DATA_NULL.getMsg());

            Result<Integer> accountIdByVenueId = vc.findAccountIdByVenueId(co.getVenueId());
            if(accountIdByVenueId.getData()==null)
                throw new MyException(FundExceptionCode.RETURN_DATA_NULL.getCode(),FundExceptionCode.RETURN_DATA_NULL.getMsg());

            AutoDeductMoneyInfo autoDeductMoneyInfo = new AutoDeductMoneyInfo();
            autoDeductMoneyInfo.setDeductionId(accountIdByVenueId.getData());
            autoDeductMoneyInfo.setAddId(accountIdByStudentId.getData());
            autoDeductMoneyInfo.setMoneyAmount(new BigDecimal(bp.getCashAmount()));
            Result result2 = userClient.autoDeductMoney(autoDeductMoneyInfo);
            if (result2.getCode() != 200){
                a = 2;
            }
            if(result2.getCode() == 200){
                srt.opsForValue().set("return_cash:save:info:done" + co.getOrderNum(),"done");
            }
            //退款失败
            if(a!=null){
                System.out.println("进入延时任务++++++++++++++++++++++++++++++++++");
                //延时任务
                //设置演示任务和参数
                XxlJobCreateParam param = new XxlJobCreateParam();
                param.setExecutorId(2);
                param.setJobDesc("订单退款复核");
                RefundInfo refundInfo = new RefundInfo();
                refundInfo.setOrderNum(co.getOrderNum());
                refundInfo.setVenueId(co.getVenueId());
                param.setExecutorParam(new ObjectMapper().writeValueAsString(refundInfo));
                param.setScheduleConf(dateToCron(LocalDateTime.now().plusSeconds(10)));
                param.setExecutorHandler("closeVenueByOrderState");
                int jobId = xxl.createJob(param);
                System.out.println(jobId+"111111111111111");
                //存缓存 存个jobid order
              srt.opsForValue().set(co.getOrderNum(),jobId+"");
                return new Result().setCode(FundExceptionCode.REFUND_FAIL.getCode()).setMsg("用户支付宝余额不足或密码不足，请充值");
            }
        }

        //别上面存 下面取
        String jobId = srt.opsForValue().get(corder.getData().getOrderNum());
        if(jobId!=null){
            srt.delete(jobId+"");
            xxl.removeJob(Integer.parseInt(jobId));
        }

        //异步回调根据订单id 更改订单状态为已退款  //异步回调 第二次
        RechargeStateInfo rechargeStateInfo = new RechargeStateInfo();
        rechargeStateInfo.setSericalNum(serialNum);
        rechargeStateInfo.setOut_trade_no(co.getOrderNum());
        rechargeStateInfo.setScenceId(co.getId());
        rechargeStateInfo.setScence(SchemaCode.REFUND_CODE.getNum());
        rechargeStateInfo.setPayment(co.getPayment());
        rechargeStateInfo.setCashAmount(new BigDecimal(bp.getCashAmount()));
        rechargeStateInfo.setState(10);
        System.out.println(co);
        rechargeStateInfo.setPayerId(data);
        rechargeStateInfo.setPayeeId(uid);
        rechargeStateInfo.setPayeeName(co.getStudentName());
        rechargeStateInfo.setPayerName(userName);

        Message<RechargeStateInfo> message = MessageBuilder.withPayload(rechargeStateInfo)
                .build();
        rt.asyncSend("msgsend:add_info",message,
                new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        System.out.println("发送成功: " + sendResult);
                    }
                    @Override
                    public void onException(Throwable e) {
                        System.out.println("发送失败: " + e.getMessage());
                    }

                });
        //添加参数 返回前端 不用等更改订单状态成功
        BalancePayDto balancePayDto = new BalancePayDto();
        balancePayDto.setCashAmount(co.getPrice());
        balancePayDto.setOrderNum(co.getOrderNum());
        balancePayDto.setCreateTime(LocalDateTime.now());
        balancePayDto.setDealStyle("退款");
        return new Result<BalancePayDto>().setCode(200).setMsg("退款成功").setData(balancePayDto);
    }

    @Override
    public Result sendRefundRequest(@Valid SendRefundRequest srr) {
        //获取账户信息
        //根据token 查用户id 用户名
        LoginUserDto userDto = GetTokenUserLogin.getTokenUserLogin();
        //前台帐户id
        Integer uid = userDto.getLoginId();
        //前台帐户用户名
        String userName = userDto.getLoginName();

        Result<StudentInfo> studentByAccountId = sc.findStudentByAccountId(uid);
        if(studentByAccountId.getCode()!=200)
            throw new MyException(FundExceptionCode.USER_NOT_FOUND.getCode(),FundExceptionCode.USER_NOT_FOUND.getMsg());
        StudentInfo data = studentByAccountId.getData();
        if(data==null)
            throw new MyException(FundExceptionCode.RETURN_DATA_NULL.getCode(),FundExceptionCode.RETURN_DATA_NULL.getMsg());
        Result<ClassesOrderDto> classesOrderById = coc.getClassesOrderById(srr.getOrderId());
        ClassesOrderDto co = classesOrderById.getData();
        if(co==null)
            throw new MyException(FundExceptionCode.ORDER_NULL.getCode(),FundExceptionCode.ORDER_NULL.getMsg());
        if(co.getStudentId().intValue()!=data.getId().intValue())
            throw new MyException(FundExceptionCode.NOT_THIS_STUDENT.getCode(),FundExceptionCode.NOT_STU_ORDER.getMsg());
        //已支付才能发起退款
        if(co.getState()!=1)
            throw new MyException(FundExceptionCode.ORDER_NOT_PAY.getCode(),FundExceptionCode.ORDER_NOT_PAY.getMsg());
        //该订单是否已发起申请
        if(co.getState()==14)
            throw new MyException(FundExceptionCode.ORDER_HAD_COMMIT.getCode(),FundExceptionCode.ORDER_HAD_COMMIT.getMsg());
        Result result = coc.changeOrderState(co.getId(), 14, co.getPayment(), DateUtil.timeFormatString(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"));
        System.out.println(result);


        return new Result().setCode(200).setMsg("退款申请成功");
    }

    public String dateToCron(LocalDateTime date) {
        String cronFormat = "ss mm HH dd MM ? yyyy";
        return DateTimeFormatter.ofPattern(cronFormat).format(date);
    }

}

